<!--
 * Copyright © 2023
 * @Author: zhangxiang
 * @Date: 2023-07-23 17:34:57
 * @LastEditors: zhangxiang
 * @LastEditTime: 2023-09-04 14:00:48
 * @Description:
 *
-->

<template>
  <el-form
    ref="form"
    class="vm-form-aliyun"
    :rules="rules"
    :model="form"
    label-width="110px"
    size="medium"
  >
    <el-form-item
      v-if="scene != 'orchestrate'"
      class="item"
      label="云服务商"
      prop="cloudProvider"
    >
      <el-select
        v-model="form.cloudProvider"
        placeholder="请选择云服务商"
        style="width: 100%"
        :disabled="true"
      >
        <el-option
          v-for="item in cloudProviderOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
    </el-form-item>
    <el-form-item
      v-if="scene != 'orchestrate'"
      class="item right"
      label="云账户"
      prop="cloudAccountName"
    >
      <el-select
        v-model="form.cloudAccountName"
        placeholder="请选择云账户"
        style="width: 100%"
        no-data-text="请选择云服务商"
      >
        <el-option
          v-for="item in cloudAccountNameOptions"
          :key="item.cloudAccountName"
          :label="item.cloudAccountName"
          :value="item.cloudAccountName"
        />
      </el-select>
    </el-form-item>
    <el-form-item label="主机名称" prop="vmName">
      <el-row type="flex" align="middle">
        <el-input v-model="form.vmName" placeholder="请输入主机名称" />
        <el-popover placement="right" width="250" trigger="hover">
          <p v-html="nameRule"></p>
          <i
            slot="reference"
            class="el-icon-info icon"
            style="font-size: 18px; margin-left: 10px"
          ></i>
        </el-popover>
      </el-row>
    </el-form-item>
    <el-form-item label="计费模式" prop="chargeParam">
      <el-row type="flex" align="middle" style="height: 36px">
        <el-radio-group
          v-model="form.chargeType"
          size="small"
          @input="chargeTypeChange"
        >
          <el-radio
            v-for="item in chargeTypeOptions"
            :key="item.value"
            :label="item.value"
            border
          >{{ item.label }}</el-radio>
        </el-radio-group>
        <el-select
          v-if="form.chargeType === '包年包月'"
          v-model="chargePeriod"
          placeholder="请选择时长"
          style="flex: 1; margin-left: 10px"
          size="small"
        >
          <el-option
            v-for="item in chargePeriodOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </el-row>
    </el-form-item>
    <el-form-item class="item" label="区域" prop="cpRegionId">
      <el-select
        v-model="form.cpRegionId"
        placeholder="请选择区域"
        no-data-text="请选择合适的云服务商"
        style="width: 100%"
        @change="regionChange"
      >
        <el-option
          v-for="item in regionOptions"
          :key="item.cpId"
          :label="item.desc"
          :value="item.cpId"
        />
      </el-select>
    </el-form-item>
    <el-form-item class="item right" label="可用区" prop="zone">
      <el-select
        v-model="form.zone"
        placeholder="请选择可用区"
        no-data-text="请先选择区域"
        style="width: 100%"
        @change="zoneChange"
      >
        <el-option
          v-for="item in zoneOptions"
          :key="item.key"
          :label="item.text"
          :value="item.key"
        />
      </el-select>
    </el-form-item>
    <el-form-item label="镜像" prop="imageId">
      <el-row type="flex" justify="center">
        <el-select
          v-model="form.imageOs"
          placeholder="请选择操作系统"
          style="width: 30%; margin-right: 10px"
          @change="imageOsChange"
        >
          <el-option
            v-for="item in imageOsOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
        <el-select
          v-model="form.imageId"
          placeholder="请选择相应镜像"
          no-data-text="请先选择合适的区域"
          style="width: 70%"
          filterable
        >
          <el-option
            v-for="item in imageIdOptions"
            :key="item.id"
            :label="item.name"
            :value="item.id"
          />
        </el-select>
      </el-row>
    </el-form-item>
    <el-form-item label="规格" prop="flavorId">
      <el-row type="flex" justify="center">
        <el-select
          v-model="form.cpuArch"
          placeholder="请选择CPU架构"
          style="flex: 1; margin-right: 5px"
          @change="flavorSelectorChange($event, 'cpuArch')"
        >
          <el-option
            v-for="item in cpuArchOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
        <el-select
          v-model="form.cpuCount"
          placeholder="请选择vCPUs"
          style="flex: 1; margin-right: 5px"
          @change="flavorSelectorChange($event, 'cpuCount')"
        >
          <el-option
            v-for="item in cpuCountOptions"
            :key="item.value"
            :label="item.label + 'vCPUs'"
            :value="item.value"
          />
        </el-select>
        <el-select
          v-model="form.memSize"
          placeholder="请选择内存"
          style="flex: 1; margin-right: 5px"
          @change="flavorSelectorChange($event, 'memSize')"
        >
          <el-option
            v-for="item in memSizeOptions"
            :key="item.value"
            :label="item.label + 'GiB'"
            :value="item.value"
          />
        </el-select>
        <el-select
          v-model="form.flavorId"
          placeholder="请选择规格"
          no-data-text="请选择合适的区域及过滤条件"
          style="flex: 2"
          :loading="loadingFlavorIdOptions"
        >
          <el-option
            v-for="item in flavorIdOptions"
            :key="item.id"
            :label="
              item.name + ' (' + item.cpuCount + 'C | ' + item.memSize + 'G)'
            "
            :value="item.id"
          />
        </el-select>
      </el-row>
    </el-form-item>
    <el-form-item class="item" label="系统盘" prop="sysDiskType">
      <el-select
        v-model="form.sysDiskType"
        placeholder="请选择系统盘"
        style="width: 100%"
      >
        <el-option
          v-for="item in sysDiskTypeOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
    </el-form-item>
    <el-form-item class="item right sysDiskSize" label="" prop="sysDiskSize">
      <el-input-number
        v-model="form.sysDiskSize"
        class="cooldownDelay"
        :min="20"
        :max="500"
        :precision="0"
        label="系统盘大小"
      />
      <span style="margin-left: 10px">GB</span>
    </el-form-item>
    <el-form-item label="公网IP" prop="publicIp">
      <el-checkbox v-model="form.publicIp">分配公网IPv4地址</el-checkbox>
    </el-form-item>
    <template v-if="form.publicIp">
      <el-form-item label="带宽计费模式" prop="internetChargeType">
        <el-radio-group
          v-model="form.internetChargeType"
          size="small"
          @input="internetChargeTypeChange"
        >
          <el-radio
            v-for="item in internetChargeTypeOptions"
            :key="item.value"
            :label="item.value"
            border
          >{{ item.label }}</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item
        :label="
          form.internetChargeType === '按固定带宽计费' ? '带宽大小' : '带宽峰值'
        "
        prop="internetMaxBandwidthOut"
      >
        <el-input-number
          v-model="form.internetMaxBandwidthOut"
          style="width: 160px"
          :min="1"
          :max="100"
          :precision="0"
          label="带宽"
        />
        <span style="margin-left: 5px">（1M-100M）</span>
      </el-form-item>
    </template>
    <el-form-item label="登录密码" prop="loginPwd">
      <el-row type="flex" align="middle">
        <el-input v-model="form.loginPwd" placeholder="请输入登录密码" />
        <el-tooltip
          effect="dark"
          content="用于设置登录虚机的root密码"
          placement="top"
        >
          <i
            class="el-icon-info icon"
            style="font-size: 18px; margin-left: 10px"
          ></i>
        </el-tooltip>
      </el-row>
    </el-form-item>
    <el-form-item label="标签" prop="vmTags">
      <VmTags :vm-tags.sync="form.vmTags" />
    </el-form-item>
  </el-form>
</template>

<script>
import resSelectorMixin from '@/views/mixin/resSelector.js'
import {
  getRegionList,
  queryImage,
  queryInstanceType
} from '@/api/cn-resource'
import {
  CLOUD_ALI_IMAGE_OS,
  CPU_ARCH,
  VCPUS,
  MEM_SIZE
} from '@/utils/constant'
import debounce from 'lodash/debounce'
import VmTags from '@/views/cn-resource/vm/components/VmTags.vue'

const NAME_RULE =
  '长度为2-128个字符，可包含大小写字母、中文、数字、点号(.)、下划线(_)、连字符(-)、半角冒号(:)，且以大小写字母或中文开头'

export default {
  name: 'VMFormAliyun',
  components: {
    VmTags
  },
  mixins: [resSelectorMixin],
  props: {
    scene: {
      type: String,
      default: 'create'
    },
    info: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    /**
     * @description: 检验计费相关参数
     * @param {*} rule
     * @param {*} value
     * @param {*} callback
     * @return {*}
     */
    var validateChargeParam = (rule, value, callback) => {
      if (this.form.chargeType === '') {
        callback(new Error('请选择计费模式'))
      } else if (
        this.form.chargeType === '包年包月' &&
        this.chargePeriod === ''
      ) {
        callback(new Error('请选择包年包月时长'))
      } else {
        callback()
      }
    }
    /**
     * @description: 校验 登录密码
     * @param {*} rule
     * @param {*} value
     * @param {*} callback
     * @return {*}
     */
    var validateLoginPwd = (rule, value, callback) => {
      if (this.form.cloudProvider === '阿里云') {
        const reg =
          /^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_]+$)(?![a-z0-9]+$)(?![a-z\W_]+$)(?![0-9\W_]+$)[a-zA-Z0-9\W_]{8,30}$/
        if (reg.test(value)) {
          callback()
        } else {
          callback(
            new Error(
              '密码长度8~30字符，须同时包含大写字母、小写字母、数字、特殊字符中的任意三种'
            )
          ) // 抛出异常
        }
      } else if (this.form.cloudProvider === '华为云') {
        const reg =
          /^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_]+$)(?![a-z0-9]+$)(?![a-z\W_]+$)(?![0-9\W_]+$)[a-zA-Z0-9\W_]{8,26}$/
        if (reg.test(value)) {
          callback()
        } else {
          callback(
            new Error(
              '密码长度8~26字符，须同时包含大写字母、小写字母、数字、特殊字符中的任意三种'
            )
          ) // 抛出异常
        }
      } else {
        if (value === '') {
          callback(new Error('请输入密码')) // 抛出异常
        } else {
          callback()
        }
      }
    }
    /**
     * @description: 校验vmTags
     * @param {*} rule
     * @param {*} value
     * @param {*} callback
     * @return {*}
     */
    var validateVmTags = (rule, value, callback) => {
      if (Array.isArray(this.form.vmTags) && this.form.vmTags.length > 0) {
        // 不为空
        const reg = /^([a-zA-Z\d-_\\\/\:\.\s])*$/ // 校验的正则
        let hasIllegal = false // 是否存在不合法
        for (const item of this.form.vmTags) {
          if (
            item.key === '' ||
            !reg.test(item.key) ||
            item.value === '' ||
            !reg.test(item.value) // 数据为空或不符合规则
          ) {
            // 存在不合法
            hasIllegal = true
            break
          }
        }
        if (hasIllegal) {
          callback(new Error('存在不合法的标签键值')) // 抛出异常
        } else {
          callback()
        }
      } else {
        callback()
      }
    }
    return {
      nameRule: NAME_RULE,
      skipGetCloudAccount: false,
      chargeTypeOptions: [
        {
          label: '按量付费',
          value: '按量付费'
        },
        {
          label: '包年包月',
          value: '包年包月'
        }
      ],
      chargePeriod: '',
      chargePeriodOptions: [
        {
          label: '1周',
          value: '1周',
          unit: 'Week',
          period: '1'
        },
        {
          label: '1个月',
          value: '1个月',
          unit: 'Month',
          period: '1'
        },
        {
          label: '2个月',
          value: '2个月',
          unit: 'Month',
          period: '2'
        },
        {
          label: '3个月',
          value: '3个月',
          unit: 'Month',
          period: '3'
        },
        {
          label: '半年',
          value: '半年',
          unit: 'Month',
          period: '6'
        },
        {
          label: '1年',
          value: '1年',
          unit: 'Month',
          period: '12'
        },
        {
          label: '2年',
          value: '2年',
          unit: 'Month',
          period: '24'
        },
        {
          label: '3年',
          value: '3年',
          unit: 'Month',
          period: '36'
        }
      ],
      regionOptions: [],
      zoneOptions: [],
      imageOsOptions: CLOUD_ALI_IMAGE_OS,
      imageIdOptions: [],
      flavorIdOptions: [],
      loadingFlavorIdOptions: false,
      sysDiskTypeOptions: [
        {
          label: '高效云盘',
          value: '高效云盘'
        },
        {
          label: 'SSD云盘',
          value: 'SSD云盘'
        }
      ],
      cpuArchOptions: CPU_ARCH,
      cpuCountOptions: VCPUS,
      memSizeOptions: MEM_SIZE,
      internetChargeTypeOptions: [
        {
          label: '按固定带宽计费',
          value: '按固定带宽计费'
        },
        {
          label: '按使用流量计费',
          value: '按使用流量计费'
        }
      ],
      form: {
        cloudProvider: '', // 云服务商
        cloudAccountName: '', // 云账户
        vmName: '', // 主机名称
        chargeType: '', // 计费模式
        period: '',
        periodUnit: '',
        cpRegionId: '', // 区域
        zone: '', // 可用区
        imageOs: CLOUD_ALI_IMAGE_OS[0].value, // 镜像系统
        imageId: '', // 镜像
        cpuArch: '', // cpu架构
        cpuCount: '', // cpu
        memSize: '', // 内存
        flavorId: '', // 规格
        sysDiskType: '', // 系统盘
        sysDiskSize: 40, // 系统盘大小
        publicIp: true, // 分配公网IP
        internetChargeType: '按固定带宽计费', // 带宽计费模式
        internetMaxBandwidthOut: 5, // 带宽大小/带宽峰值
        loginPwd: '', // 登录密码
        vmTags: [] // 标签
      },
      rules: {
        cloudProvider: [
          { required: true, message: '请选择云服务商', trigger: 'change' }
        ],
        cloudAccountName: [
          { required: true, message: '请选择云账户', trigger: 'change' }
        ],
        vmName: [
          { required: true, message: '请输入主机名称', trigger: 'blur' },
          {
            pattern: /^(?![_\-\.\:0-9])[\u4e00-\u9fa5\-\.\:_a-zA-Z0-9]{2,128}$/,
            message: NAME_RULE
          }
        ],
        chargeParam: [
          {
            required: true,
            validator: validateChargeParam
          }
        ],
        cpRegionId: [
          { required: true, message: '请选择区域', trigger: 'change' }
        ],
        zone: [{ required: true, message: '请选择可用区', trigger: 'change' }],
        imageOs: [
          { required: true, message: '请选择操作系统', trigger: 'change' }
        ],
        imageId: [
          { required: true, message: '请选择相应镜像', trigger: 'change' }
        ],
        flavorId: [
          { required: true, message: '请选择规格', trigger: 'change' }
        ],
        sysDiskType: [
          { required: true, message: '请选择系统盘', trigger: 'change' }
        ],
        sysDiskSize: [
          { required: true, message: '请输入系统盘大小', trigger: 'blur' }
        ],
        publicIp: [{ required: true, message: '请选择是否分配公网IP' }],
        internetChargeType: [{ required: true, message: '请选择带宽计费模式' }],
        internetMaxBandwidthOut: [{ required: true, message: '请设置带宽' }],
        loginPwd: [{ required: true, validator: validateLoginPwd }],
        vmTags: [{ validator: validateVmTags }]
      },
      flavorQueryDebounce: null,
      imageIdQueryDebounce: null
    }
  },
  computed: {
    /**
     * @description: 规格相关参数
     * @return {*}
     */
    flavorParam() {
      return {
        cpRegionId: this.form.cpRegionId,
        zone: this.form.zone,
        chargeType: this.form.chargeType,
        imageId: this.form.imageId,
        cpuArch: this.form.cpuArch,
        cpuCount: this.form.cpuCount,
        memSize: this.form.memSize
      }
    },
    /**
     * @description: 镜像相关参数
     * @return {*}
     */
    imageIdParam() {
      return {
        cloudAccountName: this.form.cloudAccountName,
        imageOs: this.form.imageOs,
        cpRegionId: this.form.cpRegionId
      }
    }
  },
  watch: {
    /**
     * @description: 监听
     * @return {*}
     */
    info: {
      handler(newVal) {
        if (newVal) {
          this.form = Object.assign(this.form, this.info)
        }
      },
      immediate: true,
      deep: true
    },
    /**
     * @description: 监听镜像相关参数
     * @return {*}
     */
    imageIdParam: {
      handler(newVal) {
        if (!this.imageIdQueryDebounce) {
          // 创建防抖函数
          this.imageIdQueryDebounce = debounce(() => {
            if (
              this.form.cloudAccountName &&
              this.form.cpRegionId &&
              this.form.imageOs
            ) {
              this.getImageList()
            }
          }, 300)
        }
        this.imageIdQueryDebounce()
      },
      immediate: true,
      deep: true
    },
    /**
     * @description: 监听规格相关参数
     * @return {*}
     */
    flavorParam: {
      handler(newVal) {
        if (!this.flavorQueryDebounce) {
          // 创建防抖函数
          this.flavorQueryDebounce = debounce(() => {
            if (
              this.form.cloudAccountName &&
              this.form.cpRegionId &&
              this.form.chargeType
            ) {
              this.getFlavorList()
            }
          }, 300)
        }
        this.flavorQueryDebounce()
      },
      immediate: true,
      deep: true
    },
    /**
     * @description: 监听 包年包月时长 变化
     * @return {*}
     */
    chargePeriod: {
      handler(newVal) {
        if (newVal) {
          const chargeFind = this.chargePeriodOptions.find((item) => {
            return item.value === newVal
          })
          if (chargeFind) {
            this.form.period = chargeFind.period
            this.form.periodUnit = chargeFind.unit
          } else {
            this.form.period = ''
            this.form.periodUnit = ''
          }
        } else {
          this.form.period = ''
          this.form.periodUnit = ''
        }
      },
      immediate: true,
      deep: true
    },
    /**
     * @description: 云商监听
     * @return {*}
     */
    'form.cloudProvider': {
      handler(newVal) {
        if (newVal) {
          this.getRegionList()
        }
      },
      immediate: true
    }
  },
  created() {
    this.skipGetCloudAccount = this.scene === 'orchestrate'
  },
  methods: {
    /**
     * @description: 带宽计费模式 改变
     * @param {*} val
     * @return {*}
     */
    internetChargeTypeChange(val) {
      if (val === '按固定带宽') {
        this.form.internetMaxBandwidthOut = '5'
      } else if (val === '按使用流量') {
        this.form.internetMaxBandwidthOut = '5'
      }
    },
    /**
     * @description: 计费模式 改变
     * @param {*} val
     * @return {*}
     */
    chargeTypeChange(val) {
      if (val === '按量付费') {
        this.chargePeriod = ''
      }
      // 清空规格
      this.form.flavorId = ''
      this.flavorIdOptions = []
    },
    /**
     * @description: 可用区变化
     * @param {*} val
     * @return {*}
     */
    zoneChange(val) {
      // 清空规格
      this.form.flavorId = ''
      this.flavorIdOptions = []
    },
    /**
     * @description: 获取规格
     * @return {*}
     */
    getFlavorList() {
      this.loadingFlavorIdOptions = true
      let cpImageId = ''
      if (this.form.imageId) {
        const imageSelect = this.imageIdOptions.find((item) => {
          return item.id === this.form.imageId
        })
        cpImageId = imageSelect ? imageSelect.name : ''
      }
      queryInstanceType({
        cloudProvider: this.form.cloudProvider,
        cloudAccountName: this.form.cloudAccountName,
        chargeType: this.form.chargeType,
        region: this.form.cpRegionId,
        zone: this.form.zone,
        cpImageId: cpImageId,
        cpuArch: this.form.cpuArch,
        cpuCount: this.form.cpuCount,
        memSize: this.form.memSize
      })
        .then((res) => {
          this.flavorIdOptions = Array.isArray(res.data)
            ? res.data.slice(0, Math.min(res.data.length, 100))
            : []
        })
        .finally(() => {
          this.loadingFlavorIdOptions = false
        })
    },
    /**
     * @description: 获取镜像
     * @return {*}
     */
    getImageList() {
      queryImage({
        cloudProvider: this.form.cloudProvider,
        cloudAccountName: this.form.cloudAccountName,
        osPlatform: this.form.imageOs,
        region: this.form.cpRegionId
      }).then((res) => {
        this.imageIdOptions = Array.isArray(res.data) ? res.data : []
      })
    },
    /**
     * @description: 镜像操作系统选择
     * @param {*} val
     * @return {*}
     */
    imageOsChange(val) {
      // 刷新镜像
      this.form.imageId = ''
      this.imageIdOptions = []
    },
    /**
     * @description: 规格过滤切换
     * @param {*} val
     * @param {*} type
     * @return {*}
     */
    flavorSelectorChange(val, type) {
      // 清空规格
      this.form.flavorId = ''
      this.flavorIdOptions = []
    },
    /**
     * @description: 区域变化
     * @param {*} val
     * @return {*}
     */
    regionChange(val) {
      // 刷新可用区
      this.form.zone = ''
      this.findZoneOptions()
      // 刷新镜像
      this.form.imageId = ''
      this.imageIdOptions = []
      // 清空规格
      this.form.flavorId = ''
      this.flavorIdOptions = []
    },
    /**
     * @description: 查找可用区
     * @return {*}
     */
    findZoneOptions() {
      // 查找已选择
      const regionSelect = this.regionOptions.find((item) => {
        return this.form.cpRegionId === item.cpId
      })
      // 设置可用区选项
      if (regionSelect && Array.isArray(regionSelect.zones)) {
        this.zoneOptions = regionSelect.zones.filter((item) => {
          return item.val
        })
      } else {
        this.zoneOptions = []
      }
    },
    /**
     * @description: 获取区域
     * @return {*}
     */
    getRegionList() {
      getRegionList({
        keyword: this.form.cloudProvider,
        pageNum: 1,
        pageSize: 100
      }).then((res) => {
        if (res.data) {
          this.regionOptions = Array.isArray(res.data.data)
            ? res.data.data
            : []
          if (this.form.cpRegionId) {
            this.findZoneOptions()
          }
        } else {
          this.regionOptions = []
        }
      })
    },
    /**
     * @description: 校验
     * @return {*}
     */
    validateForm(callback) {
      this.$refs.form.validate((valid, obj) => {
        if (valid) {
          callback(this.form)
        }
      })
    }
  }
}
</script>

<style lang="less" scoped>
@import "@/assets/css/common.less";
.vm-form-aliyun {
  .item {
    display: inline-block;
    width: calc(50% - 7.5px);
    &.right {
      margin-left: 15px;
    }
    &.sysDiskSize {
      /deep/ .el-form-item__content {
        margin-left: 5px !important;
      }
    }
  }
}
</style>
